#include "wrapping_integers.hh"

// Dummy implementation of a 32-bit wrapping integer

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}

using namespace std;

//! Transform an "absolute" 64-bit sequence number (zero-indexed) into a WrappingInt32
//! \param n The input absolute 64-bit sequence number
//! \param isn The initial sequence number
WrappingInt32 wrap(uint64_t n, WrappingInt32 isn) {
    return WrappingInt32((isn.raw_value() + (n & 0xffffffff)) & 0xffffffff);
}

//! Transform a WrappingInt32 into an "absolute" 64-bit sequence number (zero-indexed)
//! \param n The relative sequence number
//! \param isn The initial sequence number
//! \param checkpoint A recent absolute 64-bit sequence number
//! \returns the 64-bit sequence number that wraps to `n` and is closest to `checkpoint`
//!
//! \note Each of the two streams of the TCP connection has its own ISN. One stream
//! runs from the local TCPSender to the remote TCPReceiver and has one ISN,
//! and the other stream runs from the remote TCPSender to the local TCPReceiver and
//! has a different ISN.
uint64_t unwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint) {
    uint32_t diff = n - wrap(checkpoint, isn);
    uint64_t res = checkpoint + diff;
    if (diff >= (1u << 31) && res >= (1ul << 32)) {
        res -= (1ul << 32);
    }
    return res;
    /*int cnt = 0;
    uint64_t tmp = checkpoint;
    while (tmp >> cnt) {
        ++cnt;
    }
    uint32_t diff = n - wrap(checkpoint, isn);
    uint64_t res1 = uint64_t(n.raw_value() - isn.raw_value()) + (1ul << (cnt - 1));
    uint64_t res2 = uint64_t(n.raw_value() - isn.raw_value()) + (1ul << cnt);
    uint64_t res3 = uint64_t(isn.raw_value() - n.raw_value()) + (1ul << (cnt - 1));
    uint64_t res4 = uint64_t(isn.raw_value() - n.raw_value()) + (1ul << cnt);
    if (cnt >= 32 && n.raw_value() > isn.raw_value()) {
        if (diff >= 1u << 31)
            return res1;
        else
            return res2;
    } else if (cnt >= 32 && n.raw_value() <= isn.raw_value()) {
        if (diff >= 1u << 31)
            return res3;
        else
            return res4;
    }
    return n.raw_value() > isn.raw_value() ? n.raw_value() - isn.raw_value() : isn.raw_value() - n.raw_value();*/
}
